package cloud.health.framework.computing.gateway.domain;

import cloud.health.framework.computing.core.AbstractNettyServer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
public class Proxy extends AbstractNettyServer {

    private Integer port;

    public Proxy(int port) {
        this.port = port;
    }

    @Override
    protected int port() {
        return this.port;
    }

    @Override
    protected ChannelInitializer<SocketChannel> channelInitializer() {
        return new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                log.info("{}", ch);
                ProxyChannelHandler handler = new ProxyChannelHandler();
                ch.pipeline().addLast(handler);
            }

        };
    }

    public class ProxyChannelHandler extends ChannelInboundHandlerAdapter {

        private ChannelHandlerContext context;
        private ChannelHandlerContext proxy;

        public ChannelHandlerContext getContext() {
            return this.context;
        }

        public void setProxy(ChannelHandlerContext proxy) {
            this.proxy = proxy;
        }

        public ChannelHandlerContext getProxy() {
            return proxy;
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            this.context = ctx;
            Gateway.find(this);
            log.info("channel is active, ctx = {}", ctx);
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            log.info("channel is inactive, ctx = {}", ctx);
            if (Objects.nonNull(this.proxy)) {
                this.proxy.close();
            }
            ctx.close();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf buf = (ByteBuf) msg;
            try {
                String str = buf.toString(StandardCharsets.UTF_8);
                log.info("ctx = {}, size = {}, buf = \n{}", ctx, buf.readableBytes(), str);
                if (Objects.isNull(this.proxy)) {
                    Gateway.find(this);
                }
                this.proxy.writeAndFlush(buf.copy());
            } finally {
                buf.release();
            }
        }

    }

}
